package com.college.system.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.util.SaResult;
import com.college.common.constant.ExceptionCodeEnum;
import com.college.common.exception.BusinessException;
import com.college.common.response.CommonResult;
import com.college.common.utils.http.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;


/**
 * 全局参数、异常拦截
 *
 * @author 小C工作室
 */
@Slf4j
@RestControllerAdvice
@ResponseBody
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {

	// 全局异常拦截（拦截项目中的NotLoginException异常）
	@ExceptionHandler(NotLoginException.class)
	public SaResult handlerNotLoginException(NotLoginException nle)
			throws Exception {

		// 打印堆栈，以供调试
		nle.printStackTrace();

		// 判断场景值，定制化异常信息
		String message = "";
		if(nle.getType().equals(NotLoginException.NOT_TOKEN)) {
			message = "未提供token";
		}
		else if(nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
			message = "token无效";
		}
		else if(nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
			message = "token已过期";
		}
		else if(nle.getType().equals(NotLoginException.BE_REPLACED)) {
			message = "token已被顶下线";
		}
		else if(nle.getType().equals(NotLoginException.KICK_OUT)) {
			message = "token已被踢下线";
		}
		else {
			message = "当前会话未登录";
		}

		// 返回给前端
		return SaResult.error(message);
	}

	@ExceptionHandler(Exception.class)
	public CommonResult error(Exception e) {
		String description = "Exception异常" + RequestUtils.getUri();
		log.error(description, e);
		//未知错误
		return CommonResult.failed(ExceptionCodeEnum.ERROR);
	}

	@ExceptionHandler(BusinessException.class)
	private CommonResult doBusinessException(BusinessException e) {
		String description = "BusinessException自定义业务异常" + RequestUtils.getUri();
		log.error(description, e);
		return CommonResult.failed(ExceptionCodeEnum.ERROR, e.getMessage());
	}

	@ExceptionHandler(BindException.class)
	private CommonResult doBindException(BindException e) {
		String description = "BindException自定义业务异常" + RequestUtils.getUri();
		log.error(description, e);
		StringBuilder sb = new StringBuilder();
		BindingResult bindingResult = e.getBindingResult();
		for (FieldError fieldError : bindingResult.getFieldErrors()) {
			sb.append(fieldError.getDefaultMessage()).append(" ");
		}
		String msg = sb.toString();
		return CommonResult.failed(ExceptionCodeEnum.ERROR, msg);
	}
	@ExceptionHandler(RuntimeException.class)
	private CommonResult runtimeException(RuntimeException e) {
		String description = "RuntimeException运行时异常" + RequestUtils.getUri();
		log.error(description, e);
		return CommonResult.failed(ExceptionCodeEnum.ERROR, e.getMessage());
	}

	@ExceptionHandler(NullPointerException.class)
	public CommonResult error(NullPointerException e) {
		String description = "NullPointerException空指针异常" + RequestUtils.getUri();
		log.error(description, e);
		return CommonResult.failed(ExceptionCodeEnum.ERROR, e.getMessage());
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public CommonResult error(MethodArgumentNotValidException e) {
		String description = "MethodArgumentNotValidException参数校验异常" + RequestUtils.getUri();
		log.error(description, e);
		StringBuilder sb = new StringBuilder();
		BindingResult bindingResult = e.getBindingResult();
		for (FieldError fieldError : bindingResult.getFieldErrors()) {
			sb.append(fieldError.getDefaultMessage()).append(" ");
		}
		String msg = sb.toString();
		return CommonResult.failed(ExceptionCodeEnum.VALIDATE_FAILED, msg);
	}

	@ExceptionHandler(ConstraintViolationException.class)
	public CommonResult error(ConstraintViolationException e) {
		String description = "ConstraintViolationException参数校验异常" + RequestUtils.getUri();
		log.error(description, e);
		return CommonResult.failed(ExceptionCodeEnum.VALIDATE_FAILED, e.getMessage());
	}

}
